﻿using System;
using System.Windows.Forms;
using System.Data;
using System.Collections.Generic;
using System.Threading;

/* Notes :
 * Make sure Graph Curve gets cleared under the tabSetup Control when all grpahs added - first complete this
 * 
 * Add Histroic Test method - delete when done testing and remove from FORM Init!!!
 * 
 * select strftime('%Y/%m/%d',DATALOG15.TIMESTAMP) ,MAX(KWH) - MIN(KWH) AS KWH_CAL
from DATALOG15
where KWH > 0 and METERS_ID = 2
group by strftime("%d",TIMESTAMP)
 * http://zedgraph.dariowiz.com/indexe30a.html?title=Vertical_Bar_With_Labels_Demo
 * http://zedgraph.dariowiz.com/indexcc38.html?title=Tutorial:Bar_Chart_Demo
 * 
 */


namespace iPower
{
    partial class iPowerMain
    {
        /* Dynamic Graph Objects - Realtime */
        DynamicGraph grhRealtimeVolts = new DynamicGraph("grhRealtimeVolts");
        DynamicGraph grhRealtimeCurrent = new DynamicGraph("grhRealtimeCurrent");

        DynamicGraph grhRealtimeFreq = new DynamicGraph("grhRealtimeFreq");
        DynamicGraph grhRealtimePF = new DynamicGraph("grhRealtimePF");

        DynamicGraph grhRealtimeRealPower = new DynamicGraph("grhRealtimeRealPower");
        DynamicGraph grhRealtimeReactivePower = new DynamicGraph("grhRealtimeReactivePower");

        /* Dynamic Graph Objects - Histric Graphs */
        DynamicGraph grhHistoricVoltsLL = new DynamicGraph(6, 16, 1050, 560, "grhHistoricVolts");
        DynamicGraph grhHistoricVoltsLN = new DynamicGraph(6, 16, 1050, 560, "grhHistoricVolts");
        DynamicGraph grhHistoricCurrent = new DynamicGraph(6, 16, 1050, 560, "grhHistoricCurrent");
        DynamicGraph grhHistoricFreq = new DynamicGraph(6, 16, 1050, 560, "grhHistoricFreq");
        DynamicGraph grhHistoricPF = new DynamicGraph(6, 16, 1050, 560, "grhHistoricPF");
        DynamicGraph grhHistoricRealPower = new DynamicGraph(6, 16, 1050, 560, "grhHistoricRealPower");
        DynamicGraph grhHistoricReactivePower = new DynamicGraph(6, 16, 1050, 560, "grhHistoricReactivePower");
        

        /* Dynamic Grpah Objects - Historic Energy Graphs */
        DynamicGraph grhHistoricEnergy = new DynamicGraph(6, 16, 1050, 560, "grhHistoricEnergy");        

        /* Site and Meter Selected when Button Pressed*/
        string strRealtimeSiteSelected = "";
        string strRealtimeMeterSelected = "";
        string strRealtimeGraphVoltageSelection = "";

        /* Site and Meter Selected when Button Pressed */
        string strHistoricSiteSelected = "";
        string strHistoricMeterSelected = "";

        /* Global Variables - Modbus Values*/
        Dictionary<string, double> _dicMBValues = new Dictionary<string, double>();
        bool _bgdWorkerFinished = false;

        // Used with DataCollector
        bool _TestButtonPressed = false;
        int _TimerSchedularCounter = 0;

        //Modbus Parms
        int mbTimeOut = 5000;
        int mbRetry = 3;

        // Assign Graphs to Controls
        public void assignGraphControls()
        {
            // Assign Graphs to GroupBox Controls - Realtime
            this.grhRealtimeVolts.assignGraph(grpBoxRealtimeGraphVolts);
            this.grhRealtimeCurrent.assignGraph(grpBoxRealtimeGraphCurrent);
            this.grhRealtimeFreq.assignGraph(grpBoxRealtimeGraphFreq);
            this.grhRealtimePF.assignGraph(grpBoxRealtimeGraphPF);
            this.grhRealtimeRealPower.assignGraph(grpBoxRealtimeGraphRealPower);
            this.grhRealtimeReactivePower.assignGraph(grpBoxRealtimeGraphReactivePower);

            // Set default graph properties - Realtime
            this.grhRealtimeVolts.setGraphPane("Voltage Graph", "Time (Sample Rate x Points)", "Voltage (V)");
            this.grhRealtimeVolts.createRealtimeCurves("Phase V1", "Phase V2", "Phase V3", 3600);

            this.grhRealtimeCurrent.setGraphPane("Current Graph", "Time (Sample Rate x Points)", "Current (I)");
            this.grhRealtimeCurrent.createRealtimeCurves("Phase I1", "Phase I2", "Phase I3", "Phase N", 3600);

            this.grhRealtimeFreq.setGraphPane("Frequency Graph", "Time (Sample Rate x Points)", "Frequency (Hz)");
            this.grhRealtimeFreq.createRealtimeCurves("Frequency - Hz", 3600);

            this.grhRealtimePF.setGraphPane("Power Factor Graph", "Time (Sample Rate x Points)", "PF");
            this.grhRealtimePF.createRealtimeCurves("Power Factor", 3600);

            this.grhRealtimeRealPower.setGraphPane("Real Power Graph", "Time (Sample Rate x Points)", "RealPower (KW)");
            this.grhRealtimeRealPower.createRealtimeCurves("Phase kW1", "Phase kW2", "Phase kW3", 3600);

            this.grhRealtimeReactivePower.setGraphPane("Reactive Power Graph", "Time (Sample Rate x Points)", "Reactive Power (KVA)");
            this.grhRealtimeReactivePower.createRealtimeCurves("Phase KVA1", "Phase KVA2", "Phase KVA3", 3600);

            //Historic Graph Curve Creation
            
            this.grhHistoricVoltsLL.createHistoricCurves("V1LL", "V2LL", "V3LL");
            this.grhHistoricVoltsLN.createHistoricCurves("V1LN", "V2LN", "V3LN");
            this.grhHistoricCurrent.createHistoricCurves("I1", "I2", "I3", "IN");
            this.grhHistoricFreq.createHistoricCurves("Hz");
            this.grhHistoricPF.createHistoricCurves("PF");
            this.grhHistoricRealPower.createHistoricCurves("KW-Line1", "KW-Line2", "KW-Line3");
            this.grhHistoricReactivePower.createHistoricCurves("KVA-Line1", "KVA-Line2", "KVA-Line3"); 
          

            // Historic Energy Graphs
            this.grhHistoricEnergy.createHistoricBarCurves("KWh","KVAh","KVARh");            

        } //assignGraphControls

        private void cmdRealtimeStart_Click(object sender, EventArgs e)
        {
            if (cmdRealtimeStart.Text == "Start")
            {
                if (cboRealtimeSample.Text != "" && strRealtimeGraphVoltageSelection != "" &&
                    strRealtimeSiteSelected != "" && strRealtimeMeterSelected != "")
                {
                    // Clear Curves in Pane
                    this.grhRealtimeVolts.clearCurves();
                    this.grhRealtimeCurrent.clearCurves();

                    this.grhRealtimeFreq.clearCurves();
                    this.grhRealtimePF.clearCurves();

                    this.grhRealtimeRealPower.clearCurves();
                    this.grhRealtimeReactivePower.clearCurves();

                    //Disable controls while running
                    cboRealtimeSample.Enabled = false;
                    cboRealtimeVoltsSel.Enabled = false;

                    //Disable MainControl Tab Selection
                    tabHistoric.Enabled = false;
                    tabSetup.Enabled = false;

                    //Disable Buttons
                    cmdRealtimeSites.disableButtons();
                    cmdRealtimeMeters.disableButtons();

                    // Start Background Worker to Get Modbus Values Once
                    bgdRealtimeWorker.RunWorkerAsync();

                    // Start Timer
                    tmrRealTimeChart.Start();                 

                } //if
                else
                {
                    MessageBox.Show("Please Select Sample Time|Voltage|Site|Meter", "Realtime Sample", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }//else

                cmdRealtimeStart.Text = "Stop";
                return;
            } //if start

            if (cmdRealtimeStart.Text == "Stop")
            {
                // Stop Timer
                tmrRealTimeChart.Stop();

                // Stop Background Worker Process
                bgdRealtimeWorker.CancelAsync();
                _bgdWorkerFinished = false;                

                // Enable controls again
                cboRealtimeSample.Enabled = true;
                cboRealtimeVoltsSel.Enabled = true;

                // Enable MainControl Tab Selection
                tabHistoric.Enabled = true;
                tabSetup.Enabled = true;

                // Enable Button Selection
                cmdRealtimeSites.enableButtons();
                cmdRealtimeMeters.enableButtons();

                // Change Text of Button
                cmdRealtimeStart.Text = "Start";

                // Clear Site Strings 
                strRealtimeSiteSelected = "";
                strRealtimeMeterSelected = "";

                // Delete Buttons
                cmdRealtimeSites.deleteButtons(this.grpBoxRealtimeSites, cmdRealtimeSitesEventHandler);
                cmdRealtimeMeters.deleteButtons(this.grpBoxRealtimeMeters, cmdRealtimeMetersEventHandler);

                // Recreate Buttons
                tabControlMain_Click(tabControlMain, EventArgs.Empty);

                // Clear Debug ListBox
                lstBoxRealtimeDebugInfo.Items.Clear();
                
                return;
            } //if stop
        }//cmdRealtimeStart_Click

        private void cboRealtimeVoltsSel_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (cboRealtimeVoltsSel.Text)
            {
                case "L - N"    :
                    strRealtimeGraphVoltageSelection = "LN";

                    //this.grhRealtimeVolts.setGraphPane("Voltage - Line to Neutral : Graph", "Time (Sample Rate x Points)", "Voltage (V)");
                break;

                case "L - L"    :
                    strRealtimeGraphVoltageSelection = "LL";
                    //this.grhRealtimeVolts.setGraphPane("Voltage - Line to Line : Graph", "Time (Sample Rate x Points)", "Voltage (V)");
                break;
            } //switch
        }//cboRealtimeVoltsSel_SelectedIndexChanged

        // Timers Sample Time Assignment
        private void cboRealtimeSample_SelectedIndexChanged(object sender, EventArgs e)
        {
            tmrRealTimeChart.Interval = (int)TimeSpan.FromSeconds(Convert.ToDouble(cboRealtimeSample.Text)).TotalMilliseconds;
        } //cboRealtimeSample_SelectedIndexChanged

        // Timer Control - Update Chart
        private void tmrRealTime_Tick(object sender, EventArgs e)
        {
            // Start Background Worker to Get Modbus Values
            if (bgdRealtimeWorker.IsBusy != true)
            {
                bgdRealtimeWorker.RunWorkerAsync();
            }//if

            // Wait to finish atleast once
            if (_bgdWorkerFinished == true)
            {
                /* Voltage Selection */
                switch (strRealtimeGraphVoltageSelection)
                {
                    case "LN":
                        this.grhRealtimeVolts.updateRealtimeCurves(_dicMBValues["V_LN1"], _dicMBValues["V_LN2"], _dicMBValues["V_LN3"]);
                        break;
                    case "LL":
                        this.grhRealtimeVolts.updateRealtimeCurves(_dicMBValues["V_LL1"], _dicMBValues["V_LL2"], _dicMBValues["V_LL3"]);
                        break;
                } //switch

                /*Current Selection*/
                this.grhRealtimeCurrent.updateRealtimeCurves(_dicMBValues["I1"], _dicMBValues["I2"], _dicMBValues["I3"], _dicMBValues["NI"]);

                /*Frequency & Power Factor*/
                this.grhRealtimeFreq.updateRealtimeCurves(_dicMBValues["FREQ"]);
                this.grhRealtimePF.updateRealtimeCurves(_dicMBValues["PF"]);

                /*Power - Real & Reactive*/
                this.grhRealtimeRealPower.updateRealtimeCurves(_dicMBValues["KW1"], _dicMBValues["KW2"], _dicMBValues["KW3"]);
                this.grhRealtimeReactivePower.updateRealtimeCurves(_dicMBValues["KVA1"], _dicMBValues["KVA2"], _dicMBValues["KVA3"]);
            }//if

        } //tmrRealTimeGraph_Tick


        // Background Worker Process - Working Part
        private void bgdRealtimeWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            /* Create Instance Mobus Object */
            // Modbus Object to query data & Database Query
            ModbusQuery mbQuery = new ModbusQuery();
            iPowerDBQuery dbQuery = new iPowerDBQuery();

            List<string> listDebug = new List<string>();

            // Return Value Dictionary
            Dictionary<string, double> dicMBValues = new Dictionary<string, double>();

            // References to Dictionary Data Types for DB Values 
            Dictionary<string, string> DBComPort;
            Dictionary<string, string> DBMeterReg;
            Dictionary<string, string> DBMeterDatatype;
            Dictionary<string, string> DBMeterScale;

            // Get References for Sites, Meters
            DBComPort = dbQuery.getSelectedDBComPort(strRealtimeSiteSelected, strRealtimeMeterSelected);
            DBMeterReg = dbQuery.getSelectedDBMeterReg(strRealtimeSiteSelected, strRealtimeMeterSelected);
            DBMeterDatatype = dbQuery.getSelectedDBMeterDatatype(strRealtimeSiteSelected, strRealtimeMeterSelected);
            DBMeterScale = dbQuery.getSelectedDBMeterScale(strRealtimeSiteSelected, strRealtimeMeterSelected);

            // Open ComPort to Selected Meter
            mbQuery.createPort(DBComPort["PORT"], Convert.ToInt32(DBComPort["BAUD"]), DBComPort["PARITY"], Convert.ToInt32(DBComPort["DATABITS"]), Convert.ToInt32(DBComPort["STOPBITS"]), listDebug);

            // Report Back To Background Progress Handler
            bgdRealtimeWorker.ReportProgress(12);

            // Get Modbus Reg
            dicMBValues.Add("V_LN1", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V1LN"]), DBMeterDatatype["V1LN"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("V_LN2", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V2LN"]), DBMeterDatatype["V2LN"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("V_LN3", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V3LN"]), DBMeterDatatype["V3LN"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));

            // Report Back To Background Progress Handler
            bgdRealtimeWorker.ReportProgress(24);

            dicMBValues.Add("V_LL1", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V1LL"]), DBMeterDatatype["V1LL"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("V_LL2", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V2LL"]), DBMeterDatatype["V2LL"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("V_LL3", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V3LL"]), DBMeterDatatype["V3LL"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));

            // Report Back To Background Progress Handler
            bgdRealtimeWorker.ReportProgress(36);

            dicMBValues.Add("I1", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["I1"]), DBMeterDatatype["I1"], Convert.ToUInt16(DBMeterScale["I"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("I2", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["I2"]), DBMeterDatatype["I2"], Convert.ToUInt16(DBMeterScale["I"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("I3", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["I3"]), DBMeterDatatype["I3"], Convert.ToUInt16(DBMeterScale["I"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("NI", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["NI"]), DBMeterDatatype["NI"], Convert.ToUInt16(DBMeterScale["I"]), this.mbTimeOut, this.mbRetry, listDebug));

            // Report Back To Background Progress Handler
            bgdRealtimeWorker.ReportProgress(48);

            dicMBValues.Add("FREQ", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["FREQ"]), DBMeterDatatype["FREQ"], Convert.ToUInt16(DBMeterScale["Hz"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("PF", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["PF"]), DBMeterDatatype["PF"], 1, this.mbTimeOut, this.mbRetry, listDebug));

            // Report Back To Background Progress Handler
            bgdRealtimeWorker.ReportProgress(60);

            dicMBValues.Add("KW1", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KW1"]), DBMeterDatatype["KW1"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("KW2", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KW2"]), DBMeterDatatype["KW2"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("KW3", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KW3"]), DBMeterDatatype["KW3"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));

            // Report Back To Background Progress Handler
            bgdRealtimeWorker.ReportProgress(72);

            dicMBValues.Add("KVA1", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KVA1"]), DBMeterDatatype["KVA1"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("KVA2", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KVA2"]), DBMeterDatatype["KVA2"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));
            dicMBValues.Add("KVA3", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KVA3"]), DBMeterDatatype["KVA3"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));

            // Report Back To Background Progress Handler
            bgdRealtimeWorker.ReportProgress(84);

            // Close ComPort -- review lock issues maybe!!!
            mbQuery.closePort();

            // Report Back To Background Progress Handler
            bgdRealtimeWorker.ReportProgress(100, listDebug);
            //listDebug.Clear();

            // Return Digtionary Values to Background WorkerCompleted
            e.Result = dicMBValues;           
        } //bgdRealtimeWorker_DoWork

        // Background Worker Progress
        private void bgdRealtimeWorker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            // Exception Messages and Exist
            if((List<string>)e.UserState != null)
            {
                foreach (string item in (List<string>)e.UserState)
                {
                    lstBoxRealtimeDebugInfo.Items.Add(item);
                }//foreach
            }//if

            // Select Most Recent Items
            lstBoxRealtimeDebugInfo.SelectedIndex = lstBoxRealtimeDebugInfo.Items.Count - 1;

            // Update Progress Bar
            pgrBarRealtime.Value = e.ProgressPercentage;
        } //bgdRealtimeWorker_ProgressChanged

        // Background Worker Process - Data Return
        private void bgdRealtimeWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            // Make Sure Dictionary is Cleared
            _dicMBValues.Clear();

            // Copy Results into Global Dictionary
            foreach(KeyValuePair<string, double> pair in (Dictionary<string, double>)e.Result)
            {                
                //Copy Values to Global Dictionary
                _dicMBValues.Add(pair.Key,pair.Value);
            } //foreach

            //Set Flag that done atleast once
            _bgdWorkerFinished = true;
            pgrBarRealtime.Value = 0;
        } //bgdRealtimeWorker_RunWorkerCompleted

        // ---------------------------------------------------------------------------------------------------------- //
        /* Data Collector Start Here*/

        // Event Handler for Data Collector
        private void cmdDataCollectorRun_Click(object sender, EventArgs e)
        {
            // Status Indication
            if (cmdDataCollectorRun.Text == "Enable")
            {
                // Set Timer Interval - Schedular
                tmrDataCollectorScheduler.Interval = (int)TimeSpan.FromMinutes(5).TotalMilliseconds;

                // Set Timers Intervals - sequentially fired
                tmrDataCollector15.Interval = (int)TimeSpan.FromMinutes(15).TotalMilliseconds;
                tmrDataCollector30.Interval = (int)TimeSpan.FromMinutes(30).TotalMilliseconds;
                tmrDataCollector60.Interval = (int)TimeSpan.FromMinutes(60).TotalMilliseconds;

                // Clear List Box
                lstBoxDataCollector.Items.Clear();
                lstBoxDataLogExceptions.Items.Clear();

                // Status Indication
                lstBoxDataCollector.Items.Add(String.Format("{0} : cmdDataCollectorRun:ENABLE",DateTime.Now));

                //Disable Test/Query
                cmdDataCollectorTest.Enabled = false;
                cboDataCollectorInterval.Enabled = false;

                // Set Disable Function
                cmdDataCollectorRun.Text = "Disable";

                // Status Report
                lstBoxDataCollector.Items.Add(String.Format("{0} : cmdDataCollectorRun:tmrDataCollectorScheduler", DateTime.Now));

                // Start DataCollector
                tmrDataCollectorScheduler.Start();

                return;
            } //Enable

            if (cmdDataCollectorRun.Text == "Disable")
            {
                // Status Indication
                lstBoxDataCollector.Items.Add(String.Format("{0} : cmdDataCollectorRun:DISABLE",DateTime.Now));

                //Stop Timers
                tmrDataCollector15.Stop();                
                tmrDataCollector30.Stop();                
                tmrDataCollector60.Stop();
                tmrDataCollectorScheduler.Stop();

                // Stop Background Worker Process
                bgdDataCollectorWorker.CancelAsync();

                // Set Enable Function Again
                cmdDataCollectorRun.Text = "Enable";

                // Enable Test/Query
                cmdDataCollectorTest.Enabled = true;
                cboDataCollectorInterval.Enabled = true;
                return;
            } //Disable

        } //cmdDataCollectorRun_Click
        
        private void cmdDataCollectorTest_Click(object sender, EventArgs e)
        {
            // Clear List Box
            lstBoxDataCollector.Items.Clear();
            lstBoxDataLogExceptions.Items.Clear();

            if (cboDataCollectorInterval.Text != "")
            {
                // Call Data Collector Thread
                if (bgdDataCollectorWorker.IsBusy != true)
                {
                    // Disable Test Button Till Complete
                    cmdDataCollectorTest.Enabled = false;
                    
                    // Global Status bit to enable Button Again
                    _TestButtonPressed = true;

                    // Start DataCollector
                    bgdDataCollectorWorker.RunWorkerAsync(cboDataCollectorInterval.Text);
                }//if
                else
                {
                    MessageBox.Show("Data Collector Process Busy...","DataCollector Test",MessageBoxButtons.OK,MessageBoxIcon.Warning);
                }//else
                cboDataCollectorInterval.SelectedIndex = -1;
            }//if
            else
            {
                MessageBox.Show("Select Interval","Data Collector Test",MessageBoxButtons.OK,MessageBoxIcon.Exclamation);
            }//else
        }//cmdDataCollectorTest_Click

        private void tmrDataCollectorScheduler_Tick(object sender, EventArgs e)
        {
            switch (_TimerSchedularCounter)
            {
                case    0   :
                    // Increment Counter
                    _TimerSchedularCounter++;

                    tmrDataCollector15.Start();
                    break;

                case    1   :
                    // Increment Counter
                    _TimerSchedularCounter++;

                    tmrDataCollector30.Start();
                    break;

                case    2   :
                    // Increment Counter
                    _TimerSchedularCounter++;

                    tmrDataCollector60.Start();
                    break;

                case    3   :

                    //Reset the Schedular Count Value
                    _TimerSchedularCounter = 0;

                    // Also Stop the Timer
                    tmrDataCollectorScheduler.Stop();
                    break;

                default     :
                    //Reset the Schedular Count Value
                    _TimerSchedularCounter = 0;

                    // Also Stop the Timer
                    tmrDataCollectorScheduler.Stop();
                    break;
            } //switch
        } //tmrDataCollectorScheduler_Tick

        private void bgdDataCollectorWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            // Wait for other Threads to finish
            Thread.Sleep((int)TimeSpan.FromMinutes(1).TotalMilliseconds);

            /* Create Instance Mobus Object */
            // Modbus Object to query data & Database Query
            ModbusQuery mbQuery = new ModbusQuery();
            iPowerDBQuery dbQuery = new iPowerDBQuery();

            List<string> listDebug = new List<string>();
            List<string> listDataLogger = new List<string>();

            // List Containers to Hold Sites & Meters
            List<string> listSites = new List<string>();
            List<string> listMeters = new List<string>();

            // Return Value Dictionary
            Dictionary<string, double> dicMBValues = new Dictionary<string, double>();            

            // References to Dictionary Data Types for DB Values 
            Dictionary<string, string> DBComPort;
            Dictionary<string, string> DBMeterReg;
            Dictionary<string, string> DBMeterDatatype;
            Dictionary<string, string> DBMeterScale;

            // String Argument from Caller
            string strCallerArgument = (string)e.Argument;

            // Get all Valid Sites with Meters
            listSites = dbQuery.getSites();

            // Clear DataLogger
            listDataLogger.Clear();

            // Check if Sites does Exist
            if (listSites.Count != 0)
            {
                // Iterate Over all Sites and get Meter Data
                foreach (string strSites in listSites)
                {
                    // Get all Meters for Specific Site and Time Interval
                    listMeters = dbQuery.getMeters(strSites, strCallerArgument);

                    if (listMeters.Count != 0)
                    {
                        foreach (string strMeters in listMeters)
                        {
                            // Report Back To Background Progress Handler
                            bgdDataCollectorWorker.ReportProgress(25);

                            // Get References for Sites, Meters
                            DBComPort = dbQuery.getSelectedDBComPort(strSites, strMeters);
                            DBMeterReg = dbQuery.getSelectedDBMeterReg(strSites, strMeters);
                            DBMeterDatatype = dbQuery.getSelectedDBMeterDatatype(strSites, strMeters);
                            DBMeterScale = dbQuery.getSelectedDBMeterScale(strSites, strMeters);

                            // Clear Dictionary Container
                            dicMBValues.Clear();
                            listDebug.Clear();

                            // Open ComPort to Selected Meter
                            mbQuery.createPort(DBComPort["PORT"], Convert.ToInt32(DBComPort["BAUD"]), DBComPort["PARITY"], Convert.ToInt32(DBComPort["DATABITS"]), Convert.ToInt32(DBComPort["STOPBITS"]), listDebug);

                            // Get Modbus Reg
                            dicMBValues.Add("V1LL", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V1LL"]), DBMeterDatatype["V1LL"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("V2LL", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V2LL"]), DBMeterDatatype["V2LL"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("V3LL", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V3LL"]), DBMeterDatatype["V3LL"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));

                            dicMBValues.Add("V1LN", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V1LN"]), DBMeterDatatype["V1LN"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("V2LN", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V2LN"]), DBMeterDatatype["V2LN"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("V3LN", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["V3LN"]), DBMeterDatatype["V3LN"], Convert.ToUInt16(DBMeterScale["V"]), this.mbTimeOut, this.mbRetry, listDebug));

                            dicMBValues.Add("I1", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["I1"]), DBMeterDatatype["I1"], Convert.ToUInt16(DBMeterScale["I"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("I2", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["I2"]), DBMeterDatatype["I2"], Convert.ToUInt16(DBMeterScale["I"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("I3", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["I3"]), DBMeterDatatype["I3"], Convert.ToUInt16(DBMeterScale["I"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("NI", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["NI"]), DBMeterDatatype["NI"], Convert.ToUInt16(DBMeterScale["I"]), this.mbTimeOut, this.mbRetry, listDebug));

                            // Report Back To Background Progress Handler
                            bgdDataCollectorWorker.ReportProgress(50);

                            dicMBValues.Add("FREQ", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["FREQ"]), DBMeterDatatype["FREQ"], Convert.ToUInt16(DBMeterScale["Hz"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("PF", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["PF"]), DBMeterDatatype["PF"], 1, this.mbTimeOut, this.mbRetry, listDebug));

                            dicMBValues.Add("KW1", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KW1"]), DBMeterDatatype["KW1"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("KW2", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KW2"]), DBMeterDatatype["KW2"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("KW3", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KW3"]), DBMeterDatatype["KW3"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));

                            dicMBValues.Add("KVA1", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KVA1"]), DBMeterDatatype["KVA1"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("KVA2", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KVA2"]), DBMeterDatatype["KVA2"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("KVA3", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KVA3"]), DBMeterDatatype["KVA3"], Convert.ToUInt16(DBMeterScale["W"]), this.mbTimeOut, this.mbRetry, listDebug));

                            dicMBValues.Add("KWH", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KWH"]), DBMeterDatatype["KWH"], Convert.ToUInt16(DBMeterScale["E"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("KVAH", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KVAH"]), DBMeterDatatype["KVAH"], Convert.ToUInt16(DBMeterScale["E"]), this.mbTimeOut, this.mbRetry, listDebug));
                            dicMBValues.Add("KVARH", mbQuery.getMobus(Convert.ToByte(DBComPort["SLAVE"]), Convert.ToUInt16(DBMeterReg["KVARH"]), DBMeterDatatype["KVARH"], Convert.ToUInt16(DBMeterScale["E"]), this.mbTimeOut, this.mbRetry, listDebug));

                            // Close ComPort
                            mbQuery.closePort();

                            // Report Back To Background Progress Handler
                            bgdDataCollectorWorker.ReportProgress(75);

                            // Depends on Argument the selection - Database Write Process
                            switch (strCallerArgument)
                            {
                                case "15":
                                    dbQuery.insDatalog(dicMBValues, strMeters, "DATALOG15");
                                    break;
                                case "30":
                                    dbQuery.insDatalog(dicMBValues, strMeters, "DATALOG30");
                                    break;

                                case "60":
                                    dbQuery.insDatalog(dicMBValues, strMeters, "DATALOG60");
                                    break;
                            }//switch

                            // Site & Meter Info
                            listDataLogger.Add(String.Format("{0}:TIMER INTERVAL={1}m queried SITE={2} for METER={3}",DateTime.Now, strCallerArgument, strSites, strMeters));

                            // Report Back To Background Progress Handler
                            bgdDataCollectorWorker.ReportProgress(100, listDebug);

                        }//foreach meters
                    }//if meters
                } //foreach sites
                // Return List to Background WorkerCompleted
                e.Result = listDataLogger;
            }//if
        } //bgdDataCollectorWorker_DoWork

        private void bgdDataCollectorWorker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            if (lstBoxDataLogExceptions.Items.Count > 100)
            {
                lstBoxDataLogExceptions.Items.Clear();
            }//if

            // Exception Messages and Exist
            if ((List<string>)e.UserState != null)
            {
                foreach (string item in (List<string>)e.UserState)
                {
                    lstBoxDataLogExceptions.Items.Add(item);
                }//foreach
            }//if

            // Select Most Recent Items
            lstBoxDataLogExceptions.SelectedIndex = lstBoxDataLogExceptions.Items.Count - 1;

            // Update Progress Bar
            pgrBarDataCollector.Value = e.ProgressPercentage;
        } //bgdDataCollectorWorker_ProgressChanged

        private void bgdDataCollectorWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            if (lstBoxDataCollector.Items.Count > 100)
            {
                lstBoxDataCollector.Items.Clear();
            }//if

            // Iterate over all String passed from Worker
            foreach (string strDataLogger in (List<string>)e.Result)
            {
                lstBoxDataCollector.Items.Add(strDataLogger);
            } //foreach 

            lstBoxDataCollector.SelectedIndex = lstBoxDataCollector.Items.Count - 1;

            // Clear ProgressBar
            pgrBarDataCollector.Value = 0;

            if (_TestButtonPressed == true)
            {
                // Enable Test Button Till Complete
                cmdDataCollectorTest.Enabled = true;

                // Enabled again, set to false
                _TestButtonPressed = false;
            }//if

            // Make Sure both workers not running
            if (bgdDataCollectorWorker.IsBusy != true && bgdRealtimeWorker.IsBusy != true)
            {
                // Start the Realtime Timer again if running
                if (cmdRealtimeStart.Text == "Stop")
                {
                    // Start Timer
                    tmrRealTimeChart.Start();
                }//if
            }//if

        } //bgdDataCollectorWorker_RunWorkerCompleted

        private void tmrDataCollector15_Tick(object sender, EventArgs e)
        {
            // Status Indication
            lstBoxDataCollector.Items.Add(String.Format("{0} : tmrDataCollector15_Tick:FIRED", DateTime.Now));

            // Stop the Realtime Timer if running
            if (cmdRealtimeStart.Text == "Stop")
            {
                // Status - Stopped Realtime timer
                lstBoxDataCollector.Items.Add(String.Format("{0} : tmrDataCollector15_Tick:STOPPED:tmrRealTimeChart", DateTime.Now));
                
                // Stop Timer & Process
                tmrRealTimeChart.Stop();
                bgdRealtimeWorker.CancelAsync();           
            }//if

            // Start Background Worker to Get Modbus Values
            if (bgdDataCollectorWorker.IsBusy != true)
            {
                // Start DataCollector
                lstBoxDataCollector.Items.Add(String.Format("{0} : tmrDataCollector15_Tick:bgdDataCollectorWorker", DateTime.Now));

                // Start background worker
                bgdDataCollectorWorker.RunWorkerAsync("15");
            }//if

        } //tmrDataCollector15_Tick

        private void tmrDataCollector30_Tick(object sender, EventArgs e)
        {
            // Status Indication
            lstBoxDataCollector.Items.Add(String.Format("{0} : tmrDataCollector30_Tick:FIRED", DateTime.Now));

            // Stop the Realtime Timer if running
            if (cmdRealtimeStart.Text == "Stop")
            {
                // Status - Stopped Realtime timer
                lstBoxDataCollector.Items.Add(String.Format("{0} : tmrDataCollector30_Tick:STOPPED:tmrRealTimeChart", DateTime.Now));

                // Start Timer
                tmrRealTimeChart.Stop();
                bgdRealtimeWorker.CancelAsync();
            }//if

            // Start Background Worker to Get Modbus Values
            if (bgdDataCollectorWorker.IsBusy != true)
            {
                // Status - Stopped Realtime timer
                lstBoxDataCollector.Items.Add(String.Format("{0} : tmrDataCollector30_Tick:START:bgdDataCollectorWorker", DateTime.Now));

                // Start background worker
                bgdDataCollectorWorker.RunWorkerAsync("30");
            }//if

        } //tmrDataCollector30_Tick

        private void tmrDataCollector60_Tick(object sender, EventArgs e)
        {
            // Status Indication
            lstBoxDataCollector.Items.Add(String.Format("{0} : tmrDataCollector60_Tick:FIRED", DateTime.Now));            

            // Stop the Realtime Timer if running
            if (cmdRealtimeStart.Text == "Stop")
            {
                // Status - Stopped Realtime timer
                lstBoxDataCollector.Items.Add(String.Format("{0} : tmrDataCollector60_Tick:STOPPED:tmrRealTimeChart", DateTime.Now));                

                // Start Timer
                tmrRealTimeChart.Stop();
                bgdRealtimeWorker.CancelAsync();
            }//if

            // Start Background Worker to Get Modbus Values
            if (bgdDataCollectorWorker.IsBusy != true)
            {
                // Status - Stopped Realtime timer
                lstBoxDataCollector.Items.Add(String.Format("{0} : tmrDataCollector60_Tick:START:bgdDataCollectorWorker", DateTime.Now));

                // Start background worker
                bgdDataCollectorWorker.RunWorkerAsync("60");
            }//if

        } //tmrDataCollector60_Tick

        /* Datacollector END HERE */
        // ---------------------------------------------------------------------------------------------------------- //

    } //class    
} //namespace